package com.rayc.mall.core.aspect;

import com.rayc.mall.core.annotation.CacheAddByUserId;
import com.rayc.mall.core.annotation.CacheRemoveByUserId;
import com.rayc.mall.common.context.UserContext;
import com.rayc.mall.core.utils.RedisUtils;
import lombok.RequiredArgsConstructor;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * @Author: Ray-C
 * @CreateTime: 2025-03-24
 * @Description: 缓存注解的切面<br>
 * {@link CacheAddByUserId}<br>
 * {@link CacheRemoveByUserId}
 * @Version: 1.0
 */
@Aspect
@Component
@RequiredArgsConstructor
public class RedisAspect {
    private final RedisUtils redisUtils;

    @Pointcut("@annotation(com.rayc.mall.core.annotation.CacheAddByUserId)")
    public void addPointcut() {
    }

    @Pointcut("@annotation(com.rayc.mall.core.annotation.CacheRemoveByUserId)")
    public void removePointcut() {
    }

    @Around("addPointcut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        // 获取方法上的注解
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        Method method = methodSignature.getMethod();
        CacheAddByUserId cacheAddByUserId = method.getAnnotation(CacheAddByUserId.class);
        if (cacheAddByUserId == null) {
            return joinPoint.proceed();
        }
        // 根据键值看是否有缓存
        // 加上用户id作为前缀
        StringBuilder key = new StringBuilder(cacheAddByUserId.key() + ":" + UserContext.getUser().toString());
        if (cacheAddByUserId.useArgs()) {
            // 把参数列表也拼接成键
            String[] parameterNames = methodSignature.getParameterNames();
            Object[] args = joinPoint.getArgs();
            for (int i = 0; i < args.length; i++) {
                key.append(":").append(parameterNames[i]).append(args[i].toString());
            }
        }
        Object redisResult = redisUtils.get(key.toString());
        if (redisResult == null) {
            // 没有缓存，添加缓存
            Object result = joinPoint.proceed();
            if (cacheAddByUserId.expireSeconds() != -1) {
                redisUtils.setEx(key.toString(), result, cacheAddByUserId.expireSeconds(), TimeUnit.SECONDS);
            } else {
                redisUtils.set(key.toString(), result);
            }
            return result;
        }
        // 有缓存，返回缓存
        return redisResult;
    }

    @Before("removePointcut()")
    public void before(JoinPoint joinPoint) {
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        Method method = methodSignature.getMethod();
        CacheRemoveByUserId cacheAddByUserId = method.getAnnotation(CacheRemoveByUserId.class);
        if (cacheAddByUserId == null) {
            return;
        }
        // 删除redis缓存
        boolean removeAll = cacheAddByUserId.removeAll();
        for (String key : cacheAddByUserId.keys()) {
            Set<String> keys = redisUtils.keys(key + "*");
            if (removeAll) {
                redisUtils.delete(keys);
            } else {
                redisUtils.delete(key + ":" + UserContext.getUser().toString());
            }
        }
    }
}
